<?php

namespace app\service;

use app\exception\ErrnoPlus;
use share\service\cache\CommonCacheKeyService;
use share\exception\ApiException;
use share\service\RedisService;

use ContentType;
use Exception;
use HttpClient;
use HttpHeader;
use HttpMethod;
use HttpRequest;
use share\exception\Errno;
use SystemHeader;
use think\Log;

class AliyunService
{
    // // 阿里云文档 https://help.aliyun.com/document_detail/177833.html?spm=a2c4g.296000.0.0.36862fc3kUHZIt
    // const TOKEN_CACHE_KEY = 'aliyun_cloud_token';

    // 获取云端资源Token
    const URL_KEY_OF_GET_TOKEN = 'cloud_token';

    // 项目下产品列表
    const URL_KEY_OF_PRODUCT_LIST = 'product_list';

    // 单个产品详情
    const URL_KEY_OF_PRODUCT_DETAIL = 'product_detail';

    // 批量获取物的列表
    const URL_KEY_OF_LIST_OF_THING = 'thing_list';


    // 获取物的属性
    const URL_KEY_OF_THING_PROPERTIES = 'thing_properties';

    // 获取物的基本信息
    const URL_KEY_OF_THING_INFO = 'thing_info';


    // 获取设备当前所在的站点
    const URL_KEY_OF_THING_REGION = 'thing_region';

    // 分页查询用户列表
    const URL_KEY_OF_USER_LIST = 'user_list';

    // 通过三方外标查询账号信息 (单个)
    const URL_KEY_OF_USER_GET_BY_OPEN_ID = 'user_get_by_open_id';

    // 获取用户绑定的设备列表详情
    const URL_KEY_OF_USER_GET_BIND_DEVICE = 'user_get_bind_device';

    // 解绑用户和设备
    const URL_KEY_OF_USER_UNBIND_DEVICE = 'user_unbind_device';

    // 强制解除设备上所有绑定关系
    const URL_KEY_OF_DEVICE_UNBIND_ALLUSER = 'device_unbind_alluser';

    // 用户批量绑定设备
    const URL_KEY_OF_USER_BATCH_BIND_DEVICE = 'device_batch_bind';

    // 根据设备ID查找绑定的用户
    const URL_KEY_OF_DEVICE_GET_BIND_USER = 'device_get_bind_user';

    // 获取用户注册的区域
    const URL_KEY_OF_GET_USER_REGION = 'get_user_region';

    // 分页查询用户列表 (倒序)
    const URL_KEY_OF_USER_LAST_LIST = 'user_last_list';

    // 查询云存储套餐
    const URL_KEY_OF_CLOUD_STORAGE_QUERY = 'cloudstorage_commodity_query';

    // 检查设备是否可以购买云存储套餐
    const URL_KEY_OF_CLOUD_STORAGE_CHECK = 'cloudstorage_commodity_check';

    // 购买云存储套餐
    const URL_KEY_OF_CLOUD_STORAGE_BUY = 'cloudstorage_commodity_buy';

    // 云存储套餐订单详情
    const URL_KEY_OF_CLOUD_STORAGE_ORDER_DETAIL = 'cloudstorage_order_get';

    // 设备的云存储套餐订单列表
    const URL_KEY_OF_CLOUD_STORAGE_ORDER_QUERY = 'cloudstorage_order_query';

    // 云存储套餐订单激活
    const URL_KEY_OF_CLOUD_STORAGE_ORDER_ENABLE = 'cloudstorage_commodity_enable';


    // 批量转移设备的region
    const URL_KEY_OF_CHANGE_REGION = 'change_region';

    // 查询免费的云存储套餐详情
    const URL_KEY_OF_GET_FREE_CLOUD_STORAGE = 'get_free_cloudstorage';


    // 领取免费的云存储套餐
    const URL_KEY_OF_CONSUME_FREE_CLOUD_STORAGE = 'consume_free_cloudstorage';


    // 设置物的属性
    const URL_KEY_OF_SET_DEVICE_PROPERTY = 'set_device_properties';
    // // 根据身份ID获取第三方Openid
    // CONST PATH_OF_GET_OPEN_ID_BY_IDENTITY = '/cloud/account/openId/getByIdentityId';
    // CONST PATH_OF_GET_OPEN_ID_BY_IDENTITY_VERSION = '1.0.4';




    public static function getAppKey()
    {
        $config = config("project");
        return $config['API']['key'];
    }

    public static function getAppSecret()
    {
        $config = config("project");
        return $config['API']['secret'];
    }

    /**
     * @var string 项目id
     */
    protected $projectId;

    /**
     * @var string 产品id
     */
    protected $productKey;

    /**
     * @var string 所属站点
     */
    protected $region;

    /**
     * 
     */
    protected function __construct($projectId, $region, $productKey)
    {
        $this->projectId = $projectId;
        $this->productKey = $productKey;
        $this->region = $region;
    }

    /**
     * @return \app\service\AliyunService
     */
    public function setProjectId($projectId)
    {
        $this->projectId = $projectId;
        return $this;
    }

    /**
     * @return \app\service\AliyunService
     */
    public function setProductKey($productKey)
    {
        $this->productKey = $productKey;
        return $this;
    }

    /**
     * @return \app\service\AliyunService
     */
    public function setRegion($region)
    {
        $this->region = $region;
        return $this;
    }

    /**
     * @return \app\service\AliyunService
     */
    public static function instance($projectId = '', $region = '', $productKey = '')
    {
        return new AliyunService($projectId, $region, $productKey);
    }

    public static function initAliyunExt()
    {
        include_once EXTEND_PATH . 'aliyun' . DIRECTORY_SEPARATOR . 'Util' . DIRECTORY_SEPARATOR . 'Autoloader.php';
    }

    public static function getDefaultProjectId()
    {
        return config('ALIYUN_DEFAULT_PROJECT_ID');
    }

    protected function aliyunRequest($path,$data,$retry = true){
        $res = $this->doAliyunRequest($path,$data);
        if($res && isset($res['code']) && $res['code'] === 200){
            return isset($res['data']) ? $res['data'] : null;
        }
        else{
            if($res && isset($res['code']) && isset($data['request']) && isset($data['request']['cloudToken']) && $data['request']['cloudToken'] && $res['code'] === 401 && $retry){  // 请求认证错误  auth error 需要重试
                $token = $this->getToken(true);             
                $data['request']['cloudToken'] =  $token;
                return $this->aliyunRequest($path,$data,false);
            }
            else{
                trace(["path" => $path, "data" => $data, "res" => $res], Log::ERROR);
                throw new ApiException("aliyun request error. path " . $path . " resp:" . json_encode($res), ErrnoPlus::COMMON_ERROR);
            }
        }
    }

    /**
     * @param string $path 
     * @param string $body
     * @return array  
     */
    protected function doAliyunRequest($path, $body)
    {
        self::initAliyunExt();
        $appkey = self::getAppKey();
        $appSecret = self::getAppSecret();
        $host = $this->getHost();
    
        $request = new HttpRequest($host, $path, HttpMethod::POST, $appkey, $appSecret);
        //设置API版本和参数，其中，res为授权的资源ID。grantType为project时，res的值为project的ID。
        //设定Content-Type
        $request->setHeader(HttpHeader::HTTP_HEADER_CONTENT_TYPE, ContentType::CONTENT_TYPE_JSON);
        //设定Accept
        $request->setHeader(HttpHeader::HTTP_HEADER_ACCEPT, ContentType::CONTENT_TYPE_JSON);
        if (strlen($body) > 0) {
            $request->setHeader(HttpHeader::HTTP_HEADER_CONTENT_MD5, base64_encode(md5($body, true)));
            $request->setBodyString($body);
        }
        //指定参与签名的header
        $request->setSignHeader(SystemHeader::X_CA_TIMESTAMP);
        $response = HttpClient::execute($request);
        // trace("response:".$response->getBody(),Log::ERROR);
        $info = @json_decode($response->getBody(), true);
        return $info;
        // if (empty($info) || $info['code'] !== 200) {
        //     trace(["response" => $response, "param" => $body, "host" => $host, "path" => $path, 'jsonBody' => $info], Log::ERROR);
        //     trace(['request', 'header' => $request->getHeaders(), 'body' => $request->getBodys()], Log::ERROR);
        //     $this->delCacheToken();
        //     throw new ApiException("aliyun request error. path " . $path . " resp:" . $response->getContent(), ErrnoPlus::COMMON_ERROR);
        // }
        // // trace([$host, $path, $appkey, $appSecret, $body,$response], "diy");
        // // trace($response, Log::ERROR);
        // return isset($info['data']) ? $info['data'] : null;
    }

    /**
     * 获取token
     */
    public function getToken($reflush = false)
    {
        if (empty($this->projectId) || empty($this->region)) {
            throw new ApiException("getToken but projectId and region no set");
        }
        $projectId = $this->projectId;
        $region = $this->region;
        $tokenCacheKey = self::getCacheKeyOfAliyunToken($region, $projectId);
        if ($reflush) {
            $this->delCacheToken();
        }
        $token = RedisService::instance(RedisService::CACHE_DB_BASE)->get($tokenCacheKey);
        if (empty($token)) {
            $tokenInfo = $this->getRawToken($projectId);
            $token = $tokenInfo['cloudToken'];
            $expire = intval($tokenInfo["expireIn"]) / 1000 - 100;
            if ($expire > 0) {
                RedisService::instance(RedisService::CACHE_DB_BASE)->set($tokenCacheKey, $token, $expire);
            }
        }
        return $token;
    }

    public function delCacheToken()
    {
        $projectId = $this->projectId;
        $region = $this->region;
        $tokenCacheKey = self::getCacheKeyOfAliyunToken($region, $projectId);
        RedisService::instance(RedisService::CACHE_DB_BASE)->del($tokenCacheKey);
    }

    public static function getCacheKeyOfAliyunToken($region, $projectId)
    {
        return CommonCacheKeyService::getCacheKey(
            CommonCacheKeyService::CACHE_KEY_ALIYUN_CLOUD_API_TOKEN,
            [
                'projectId' => $projectId,
                'region' => $region
            ]
        );
    }

    /**
     * 获取token
     * @param string $projectId
     * @return array|null 
     */
    public function getRawToken($projectId)
    {
        $token = null;
        $postData = [
            'grantType' => 'project',
            "res" => $projectId,
        ];
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_GET_TOKEN);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody),false);
    }

    /**
     * 获取产品列表
     * @param int $page 从1开始
     * @param int $size 
     */
    public function getRawProductList($page, $size)
    {
        $token = $this->getToken();
        $postData = [
            'pageNo' => $page,
            'pageSize' => $size,
        ];
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_PRODUCT_LIST);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);

        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
     * 获取产品详情信息
     * @param int $page 从1开始
     * @param int $size 
     */
    public function getRawProductDetail($productKey)
    {
        $token = null;
        $postData = [
            'productKey' => $productKey,
        ];
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_PRODUCT_DETAIL);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
     * 批量获取物的列表
     * @param string $productKey
     * @param int $status 设备状态。0（表示未激活）；1（表示在线）；3（表示离线）；8（表示禁用）。
     * @param int $page 
     * @param int $size 分页大小。取值范围：1~200。
     */
    public function getRawListOfThings($productKey, $status, $page, $size)
    {
        $token = null;
        $postData = [
            'productKey' => $productKey,
            'status' => $status,
            'currentPage' => $page,
            'pageSize' => $size,
        ];
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_LIST_OF_THING);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
     * 获取设备当前所在的站点  需要先从中国站点发出
     * @param string $productKey
     * @param string $deviceName
     */
    public function getRawThingRegoin($productKey, $deviceName)
    {
        $this->setRegion('CN'); //需要先从中国站点发出
        $token = null;
        $postData = [
            'productKey' => $productKey,
            'deviceName' => $deviceName,
        ];

        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_THING_REGION);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
     * 获取物的基本信息
     * @param string $iotId 设备ID，生活物联网平台为设备颁发的ID，设备的唯一标识符。productKey和deviceName为空时，该入参不允许为空。
     * @param string $productKey 产品的Key，设备证书信息之一。创建产品时，生活物联网平台为该产品颁发的全局唯一标识。当iotId为空时，该参数不允许为空。
     * @param string $deviceName 	设备的名称，设备证书信息之一。在注册设备时，自定义的或系统生成的设备名称，具备产品维度内的唯一性。当iotId为空时，该参数不允许为空。
     */
    public function getRawThingInfo($iotId = '', $productKey = '', $deviceName = '')
    {
        $token = null;
        $postData = [];
        if (!empty($iotId)) {
            $postData['iotId'] = $iotId;
        }
        if ((!empty($deviceName)) && (!empty($productKey))) {
            $postData['deviceName'] = $deviceName;
            $postData['productKey'] = $productKey;
        }
        if (empty($postData)) {
            throw new ApiException("设备信息为必传");
        }
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_THING_INFO);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
     * 分页查询用户列表
     */
    public function getRawUserList($offset, $count)
    {
        $token = $this->getToken();
        $postData = [];
        if ($offset) {
            $postData['offset'] = $offset;
        }
        if ($count) {
            $postData['count'] = $count;
        }
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_USER_LIST);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
     * 通过三方外标查询账号信息
     */
    public function getRawUserInfoByOpenId($openId, $openIdAppKey)
    {
        $token = null;
        $postData = [
            'openId' => $openId,
            'openIdAppKey' => $openIdAppKey,
        ];
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_USER_GET_BY_OPEN_ID);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }


    public function getUserDevice($identityId = '', $openId = '', $openIdAppKey = '', $limit = 100, $offset = 0, $isSubDevice = null, $nodeType = null)
    {
        try {
            $res = $this->getRawUserDevice($identityId, $openId, $openIdAppKey, $limit, $offset, $isSubDevice, $nodeType);
            if ($res === null) {
                $this->delCacheToken();
                return $this->getRawUserDevice($identityId, $openId, $openIdAppKey, $limit, $offset, $isSubDevice, $nodeType);
            }
            return $res;
        } catch (Exception $e) { //忽略第一次报错  
            $this->delCacheToken();
            return $this->getRawUserDevice($identityId, $openId, $openIdAppKey, $limit, $offset, $isSubDevice, $nodeType);
        }
    }

    /**
     * 获取用户绑定的设备列表详情
     * @param string $identityId 用户身份ID。openId和identityId不可同时为空，必须填写一个。
     * @param string $openId openId和identityId不可同时为空，必须填写一个。当传openId时，则openIdAppKey为必传。 
     * @param string $openIdAppKey  三方平台颁发的应用AppKey（云端唯一身份）。 
     * @param int $limit 获取个数限制，取值不可超过100。1.0.5版本新增的参数。 
     * @param int $offset 偏移量，1.0.5版本新增的参数。 
     * @param null|string $isSubDevice 是否为子设备。归属在某一个网关设备下的设备表示为子设备。取值为：true （表示获取子设备列表）；false （表示获取直连设备列表）。
     * @param string $nodeType 要查询的设备的节点类型。取值为：DEVICE（表示设备）；GATEWAY（表示网关）。 
     */
    public function getRawUserDevice($identityId = '', $openId = '', $openIdAppKey = '', $limit = 100, $offset = 0, $isSubDevice = null, $nodeType = null)
    {
        $token = $this->getToken();
        $postData = [
            'limit' => $limit,
            'offset' => $offset,
        ];
        if (!empty($identityId)) {
            $postData['identityId'] = $identityId;
        }
        if ((!empty($openId)) && (!empty($openIdAppKey))) {
            $postData['openId'] = $openId;
            $postData['openIdAppKey'] = $openIdAppKey;
        }

        if (count($postData) < 3) {
            throw new ApiException("用户省份信息为必传");
        }

        if ($isSubDevice !== null) { // true / false
            $postData['isSubDevice'] = $isSubDevice;
        }

        if (!empty($nodeType)) {
            $postData['nodeType'] = $nodeType;
        }
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_USER_GET_BIND_DEVICE);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
     * 解绑用户和设备
     * @param string $identityId 用户身份ID。openId和identityId不可同时为空，必须填写一个。
     * @param string $openId openId和identityId不可同时为空，必须填写一个。当传openId时，则openIdAppKey为必传。 
     * @param string $openIdAppKey  三方平台颁发的应用AppKey（云端唯一身份）。 
     * @param string $iotId 设备ID，生活物联网平台为设备颁发的ID，设备的唯一标识符。productKey和deviceName为空时，该入参不允许为空。
     * @param string $productKey 产品的Key，设备证书信息之一。创建产品时，生活物联网平台为该产品颁发的全局唯一标识。当iotId为空时，该参数不允许为空。
     * @param string $deviceName 	设备的名称，设备证书信息之一。在注册设备时，自定义的或系统生成的设备名称，具备产品维度内的唯一性。当iotId为空时，该参数不允许为空。
     */
    public function getRawUserUnbindDevice($identityId = '', $openId = '', $openIdAppKey = '', $iotId = '', $productKey = '', $deviceName = '')
    {
        $token = $this->getToken();
        $userData = [];
        if (!empty($identityId)) {
            $userData['identityId'] = $identityId;
        }
        if ((!empty($openId)) && (!empty($openIdAppKey))) {
            $userData['openId'] = $openId;
            $userData['openIdAppKey'] = $openIdAppKey;
        }
        if (empty($userData)) {
            throw new ApiException("用户身份信息为必传");
        }
        $deviceData = [];
        if (!empty($iotId)) {
            $deviceData['iotId'] = $iotId;
        }
        if ((!empty($deviceName)) && (!empty($productKey))) {
            $deviceData['deviceName'] = $deviceName;
            $deviceData['productKey'] = $productKey;
        }
        if (empty($deviceData)) {
            throw new ApiException("设备信息为必传");
        }

        $postData = array_merge($userData, $deviceData);

        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_USER_UNBIND_DEVICE);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
     * 强制解除设备上所有绑定关系
     * @param string $iotId 设备ID，生活物联网平台为设备颁发的ID，设备的唯一标识符。productKey和deviceName为空时，该入参不允许为空。
     * @param string $productKey 产品的Key，设备证书信息之一。创建产品时，生活物联网平台为该产品颁发的全局唯一标识。当iotId为空时，该参数不允许为空。
     * @param string $deviceName 	设备的名称，设备证书信息之一。在注册设备时，自定义的或系统生成的设备名称，具备产品维度内的唯一性。当iotId为空时，该参数不允许为空。
     */
    public function getRawUserDeviceUnbindAll($iotId = '', $productKey = '', $deviceName = '')
    {
        $token = $this->getToken();
        $postData = [];
        if (!empty($iotId)) {
            $postData['iotId'] = $iotId;
        }
        if ((!empty($deviceName)) && (!empty($productKey))) {
            $postData['deviceName'] = $deviceName;
            $postData['productKey'] = $productKey;
        }
        if (empty($postData)) {
            throw new ApiException("设备信息为必传");
        }
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_DEVICE_UNBIND_ALLUSER);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
    * https://help.aliyun.com/document_detail/296000.html?spm=a2c4g.177865.0.0.2a0276d2ux2yQY
     * 批量绑定设备
     * @param string $identityId 用户id
     * @param string|array $iotId 设备ID，生活物联网平台为设备颁发的ID，设备的唯一标识符。productKey和deviceName为空时，该入参不允许为空。
     */
    public function userBatchBind($identityId,$iotId)
    {
        $token = $this->getToken();
        $postData = [];
        if(!is_array($iotId)){
            $iotId = [$iotId];
        }
        $postData['identityId'] = $identityId;
        $deviceList = [];
        foreach($iotId as $id){
            $deviceList[] = [
                'iotId' => $id,
            ];
        }
        $postData['deviceList'] = $deviceList;
        $postData['projectId'] = $this->projectId;
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_USER_BATCH_BIND_DEVICE);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }


    /**
     * 根据设备ID查找绑定的用户
     * @param string $iotId 设备ID，生活物联网平台为设备颁发的ID，设备的唯一标识符。productKey和deviceName为空时，该入参不允许为空。
     * @param string $pageNo  	从1开始的当前查询页码。
     * @param string $pageSize 	
     */
    public function getRawUserGetBindDevice($iotId, $pageNo = 1, $pageSize = 200)
    {
        $token = null;
        $postData = [
            'iotId' => $iotId,
            'pageNo' => $pageNo,
            'pageSize' => $pageSize,
        ];

        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_DEVICE_GET_BIND_USER);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
     * 获取用户注册的区域
     * 
     */
    public function getRawUserRegoin($phone = '', $phoneLocationCode = '86', $email = '', $openId = '')
    {
        $token = $this->getToken();
        $postData = [];
        if (!empty($phone)) {
            $postData['phone'] = $phone;
        }
        if (!empty($phoneLocationCode)) {
            $postData['phoneLocationCode'] = $phoneLocationCode;
        }
        if (!empty($email)) {
            $postData['email'] = $email;
        }
        if (!empty($openId)) {
            $postData['openId'] = $openId;
        }
        if (empty($postData)) {
            throw new ApiException("请填入必要信息");
        }
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_GET_USER_REGION);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

     /**
     * 获取用户注册的区域
     * 
     */
    public function changeRegion($pk, $dn , $bindingCheck = true, $pushDeviceRegionSwitch = true)
    {
        $token = $this->getToken();
        $postData = [
            'productKey' => $pk,
            'deviceNames' => $dn,
            'bindingCheck' => $bindingCheck,
            'pushDeviceRegionSwitch' => $pushDeviceRegionSwitch,
        ];
 
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_CHANGE_REGION);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }


    /**
     * 倒序分页查询用户列表
     */
    public function getRawUserLastList($offset = 0, $count = 100)
    {
        $token = null;
        $postData = [
            'offset' => $offset,
            'count' => $count,
        ];
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_USER_LAST_LIST);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
     * 获取云存套餐信息
     */
    public function getCloudStorage()
    {
        $token = null;
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_CLOUD_STORAGE_QUERY);
        $postBody = self::makeCommonPostData(null, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
     * 购买云存
     */
    public function buyCloudStorage($iotId,$userName,$commodityCode,$specification,$copies  = 1,$extend = [])
    {
        $postData = [
            'iotId' => $iotId,
            'userName' => $userName,
            'commodityCode' => $commodityCode,
            'specification' => $specification,
            'copies' => $copies,
        ];
        if(!empty($extend)){
            $postData = array_merge($postData,$extend);
        }
        $token = $this->getToken();
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_CLOUD_STORAGE_BUY);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
     * https://help.aliyun.com/document_detail/177884.html?spm=a2c4g.177885.0.0.fbdb7652UPkd7b
     * 是否可以购买云存
     * @param string  $iotId 设备ID,生活物联网平台为设备颁发的ID,设备的唯一标识符.
     * @param string  $commodityCode 云存储套餐编码.从查询云存储套餐列表接口获取.
     * @param string  $specification 云存储套餐规格.从查询云存储套餐列表接口获取
     */
    public function isCanBuyCloudStorage($iotId, $commodityCode, $specification)
    {
        $postData = [
            'iotId' => $iotId,
            'commodityCode' => $commodityCode,
            'specification' => $specification,
        ];
        $token = $this->getToken();
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_CLOUD_STORAGE_CHECK);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
     * https://help.aliyun.com/document_detail/177886.html?spm=a2c4g.177885.0.0.4c036a4dzpFjTe
     * 获取云存储套餐的订单详情
     * @param string  $iotId 设备ID,生活物联网平台为设备颁发的ID,设备的唯一标识符.
     * @param string  $orderId 	购买云存储套餐的订单ID.
     * @param string  $deviceNoOwner 	设备是否未绑定管理员.
     */
    public function cloudStorageOrderDetail($iotId, $orderId, $deviceNoOwner = false)
    {
        $postData = [
            'iotId' => $iotId,
            'orderId' => $orderId,
        ];
        if($deviceNoOwner){
            $postData['deviceNoOwner'] = $deviceNoOwner;
        }
        $token = $this->getToken();
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_CLOUD_STORAGE_ORDER_DETAIL);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
     * https://help.aliyun.com/document_detail/177887.html?spm=a2c4g.177891.0.0.64887931O3RbvF
     * 获取云存储套餐的订单列表
     * @param string  $iotId 设备ID,生活物联网平台为设备颁发的ID,设备的唯一标识符.
     * @param int  $pageNo 		起始页数,默认为0.
     * @param int  $pageSize 	分页大小,最大值为50.
     * @param string  $deviceNoOwner 	设备是否未绑定管理员.
     */
    public function cloudStorageOrderQuery($iotId,$pageNo = 0,$pageSize = 50,$deviceNoOwner = false){
        $postData = [
            'iotId' => $iotId,
            'pageNo' => $pageNo,
            'pageSize' => $pageSize,
        ];
        if($deviceNoOwner){
            $postData['deviceNoOwner'] = $deviceNoOwner;
        }
        $token = $this->getToken();
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_CLOUD_STORAGE_ORDER_QUERY);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
     * https://help.aliyun.com/document_detail/177891.html?spm=a2c4g.177886.0.0.679e43db10CByp
     * 设置云存储套餐立即生效
     * @param string  $iotId 设备ID,生活物联网平台为设备颁发的ID,设备的唯一标识符.
     * @param string  $orderId 	购买云存储套餐的订单ID.
     */
    public function cloudStorageEnable($iotId, $orderId)
    {
        $postData = [
            'iotId' => $iotId,
            'orderId' => $orderId,
        ];
  
        $token = $this->getToken();
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_CLOUD_STORAGE_ORDER_ENABLE);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
     * 查询免费的云存储套餐详情
     */
    public function getFreeCloudStorage($iotId){
        $postData = [
            'iotId' => $iotId,
        ];
        $token = $this->getToken();
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_GET_FREE_CLOUD_STORAGE);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
     * 领取免费的云存储套餐
     */
    public function consumeFreeCloudStorage($iotId){
        $postData = [
            'iotId' => $iotId,
        ];
        $token = $this->getToken();
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_CONSUME_FREE_CLOUD_STORAGE);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }

    /**
     * 设置物的属性
     */
    public function setDeviceProperties($iotId,$pk,$dn,$properties){
        $postData = [
            'items' => $properties,
        ];
        if($iotId){
            $postData['iotId'] = $iotId;
        }
        else{
            $postData['productKey'] = $pk;
            $postData['deviceName'] = $dn;
        }
        
        $token = $this->getToken();
        $urlInfo = self::getUrlInfo(self::URL_KEY_OF_SET_DEVICE_PROPERTY);
        $postBody = self::makeCommonPostData($postData, $token, $urlInfo['version']);
        return $this->aliyunRequest($urlInfo['url'], json_encode($postBody));
    }



    public static function allHost()
    {
        return [
            //中国站
            "CN" => "https://api.link.aliyun.com",
            //新加坡站
            "SG" => "https://ap-southeast-1.api-iot.aliyuncs.com",
            //美国（弗吉尼亚）
            "US" => "https://us-east-1.api-iot.aliyuncs.com",
            //德国（法兰克林）
            "DE" => "https://eu-central-1.api-iot.aliyuncs.com"
        ];
    }

    public function getHost()
    {
        $region = strtoupper($this->region);
        // 阿里云可用站点  https://help.aliyun.com/document_detail/169790.html?spm=a2c4g.178117.0.0.4c1c7634rs0kQu
        $allHost =   self::allHost();
        return isset($allHost[$region]) ? $allHost[$region] : $allHost['CN'];
    }

    /**
     * 当前设备所在的站点.美国（弗吉尼亚）为us-east-1；新加坡为ap-southeast-1；德国（法兰克福）为germany；华东2（上海）为cn-shanghai。
     */
    public static function getRegionByLocation($regionInfo)
    {
        $region = 'CN';
        if ($regionInfo == 'us-east-1') {
            $region = 'US';
        } else if ($regionInfo == 'ap-southeast-1') {
            $region = 'SG';
        } else if ($regionInfo == 'germany') {
            $region = 'DE';
        }
        return $region;
    }

    public static function makeCommonPostData($param, $token = '', $apiVer = 'v1.0.0')
    {
        $data = [
            "id" => "1509086454180",
            "version" => "1.0",
            "request" => [
                "apiVer" => $apiVer,
            ],            
        ];
        if($param !== null){
            $data['params'] = $param;
        }
        if (!empty($token)) {
            $data['request']['cloudToken'] =  $token;
        }
        return $data;
    }

    public static function getUrlInfo($key)
    {
        $urlInfos = self::allUrlAndVersionInfo();
        return isset($urlInfos[$key]) ? $urlInfos[$key] : null;
    }

    public static function allUrlAndVersionInfo()
    {
        return [

            // 获取云端资源Token
            self::URL_KEY_OF_GET_TOKEN => [
                'url' => '/cloud/token',
                'version' => '1.0.1',
            ],

            // 项目下产品列表
            self::URL_KEY_OF_PRODUCT_LIST => [
                'url' => '/cloud/thing/productList/get',
                'version' => '1.1.2',
            ],

            // 单个产品详情
            self::URL_KEY_OF_PRODUCT_DETAIL => [
                'url' => '/cloud/thing/product/get',
                'version' => '1.1.2',
            ],

            // 批量获取物的列表
            self::URL_KEY_OF_LIST_OF_THING => [
                'url' => '/cloud/things/get',
                'version' => '1.0.2',
            ],


            // 获取物的属性
            self::URL_KEY_OF_THING_PROPERTIES => [
                'url' => '/cloud/thing/properties/get',
                'version' => '1.0.2',
            ],

            // 获取物的基本信息
            self::URL_KEY_OF_THING_INFO => [
                'url' => '/cloud/thing/info/get',
                'version' => '1.0.2',
            ],


            // 获取设备当前所在的站点
            self::URL_KEY_OF_THING_REGION => [
                'url' => '/living/cloud/device/region/get',
                'version' => '1.0.1',
            ],

            // 分页查询用户列表
            self::URL_KEY_OF_USER_LIST => [
                'url' => '/cloud/account/queryIdentityByPage',
                'version' => '1.0.4',
            ],

            // 通过三方外标查询账号信息 (单个)
            self::URL_KEY_OF_USER_GET_BY_OPEN_ID => [
                'url' => '/cloud/account/getByOpenId',
                'version' => '1.0.5',
            ],

            // 获取用户绑定的设备列表详情
            self::URL_KEY_OF_USER_GET_BIND_DEVICE => [
                'url' => '/cloud/device/queryByUser',
                'version' => '1.0.7',
            ],

            // 解绑用户和设备
            self::URL_KEY_OF_USER_UNBIND_DEVICE => [
                'url' => '/cloud/user/device/unbind',
                'version' => '1.0.5',
            ],

            // 强制解除设备上所有绑定关系
            self::URL_KEY_OF_DEVICE_UNBIND_ALLUSER => [
                'url' => '/living/cloud/user/binding/device/unbind',
                'version' => '1.0.0',
            ],

            // 用户批量绑定设备
            self::URL_KEY_OF_USER_BATCH_BIND_DEVICE => [
                'url' => '/living/cloud/user/binding/device/batch/bind',
                'version' => '1.0.1',
            ],

            // 根据设备ID查找绑定的用户
            self::URL_KEY_OF_DEVICE_GET_BIND_USER => [
                'url' => '/living/user/device/binding/query',
                'version' => '1.0.0',
            ],

            // 获取用户注册的区域
            self::URL_KEY_OF_GET_USER_REGION => [
                'url' => '/living/cloud/user/region/get',
                'version' => '1.0.1',
            ],

            // 分页查询用户列表 (倒序)
            self::URL_KEY_OF_USER_LAST_LIST => [
                'url' => '/cloud/account/queryidentitydescbypage',
                'version' => '1.0.0',
            ],



            // 查询云存储套餐列表
            self::URL_KEY_OF_CLOUD_STORAGE_QUERY => [
                'url' => '/vision/customer/cloudstorage/commodity/query',
                'version' => '1.0.4',
            ],

            // 查询云存储套餐是否可以购买
            self::URL_KEY_OF_CLOUD_STORAGE_CHECK => [
                'url' => '/vision/customer/cloudstorage/commodity/check',
                'version' => '1.0.3',
            ],


            // 购买云存储套餐
            self::URL_KEY_OF_CLOUD_STORAGE_BUY => [
                'url' => '/vision/customer/cloudstorage/commodity/buy',
                'version' => '1.0.8',
            ],


            // 获取云存储套餐的订单详情
            self::URL_KEY_OF_CLOUD_STORAGE_ORDER_DETAIL => [
                'url' => '/vision/customer/cloudstorage/order/get',
                'version' => '1.0.6',
            ],

            // 获取云存储套餐的订单列表
            self::URL_KEY_OF_CLOUD_STORAGE_ORDER_QUERY => [
                'url' => '/vision/customer/cloudstorage/order/query',
                'version' => '1.0.6',
            ],

            // 设置云存储套餐立即生效
            self::URL_KEY_OF_CLOUD_STORAGE_ORDER_ENABLE => [
                'url' => '/vision/customer/cloudstorage/commodity/enable',
                'version' => '1.0.0',
            ],

            // 查询免费的云存储套餐详情
            self::URL_KEY_OF_GET_FREE_CLOUD_STORAGE => [
                'url' => '/vision/customer/freecloudstorage/get',
                'version' => '1.0.1',
            ],

            // 领取免费的云存储套餐
            self::URL_KEY_OF_CONSUME_FREE_CLOUD_STORAGE => [
                'url' => '/vision/customer/freecloudstorage/consume',
                'version' => '1.0.4',
            ],

            // 批量把设备迁移到当前region
            self::URL_KEY_OF_CHANGE_REGION => [
                'url' => '/living/cloud/device/region/distribute',
                'version' => '1.0.0',
            ],

            // 设置物的属性
            self::URL_KEY_OF_SET_DEVICE_PROPERTY => [
                'url' => '/cloud/thing/properties/set',
                'version' => '1.0.2',
            ],
            

            
        ];
    }
}
